#ifndef __MQ_CONNECTION_
#define __MQ_CONNECTION_

#include "mq_channel.hpp"

namespace MQ
{
    class Connection
    {
    public:
        using ptr = std::shared_ptr<Connection>;

        Connection(const muduo::net::TcpConnectionPtr &conn,
                   const VirtualHost::ptr &vp,
                   const ConsumerManager::ptr cmp,
                   const ProtobufCodecPtr &codec,
                   const ThreadPool::ptr &tp)
            : _conn(conn), _vp(vp), _cmp(cmp), _codec(codec), _tp(tp)
        {
            _cp = std::make_shared<ChannelManager>();
        }

        void openChannel(const openChannelRequestPtr &req)
        {
            // 1. 判断信道ID是否重复,创建信道
            bool ret = _cp->openChannel(req->cid(), _vp, _cmp, _codec, _conn, _tp);
            if (ret == false)
            {
                LOG(ERROR, "创建信道的时候，信道ID重复了");
                return basicResponse(req->cid(), req->rid(), false);
            }
            LOG(INFO, "%s 信道创建成功！", req->cid().c_str());
            // 3. 给客户端进行回复
            basicResponse(req->cid(), req->rid(), true);
        }

        void closeChannel(const closeChannelRequestPtr &req)
        {
            _cp->closeChannel(req->cid());
            basicResponse(req->cid(), req->rid(), true);
        }

        Channel::ptr getChannel(const std::string &cid)
        {
            return _cp->getChannel(cid);
        }

    private:
        void basicResponse(const std::string &cid, const std::string &rid, bool ok)
        {
            basicCommonResponse resp;
            resp.set_cid(cid);
            resp.set_rid(rid);
            resp.set_ok(ok);
            _codec->send(_conn, resp);
        }

    private:
        muduo::net::TcpConnectionPtr _conn;
        VirtualHost::ptr _vp;
        ChannelManager::ptr _cp;
        ConsumerManager::ptr _cmp;
        ProtobufCodecPtr _codec;
        ThreadPool::ptr _tp;
    };

    class ConnectionManager
    {
    public:
        using ptr = std::shared_ptr<ConnectionManager>;
        ConnectionManager() {}
        void newConnection(const muduo::net::TcpConnectionPtr &conn, const VirtualHost::ptr &vp, const ConsumerManager::ptr &cmp, const ProtobufCodecPtr &codec, const ThreadPool::ptr &tp)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(conn);
            if (it != _conns.end())
            {
                return;
            }
            Connection::ptr self_conn = std::make_shared<Connection>(conn, vp, cmp, codec, tp);
            _conns.insert(std::make_pair(conn, self_conn));
        }

        void delConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            _conns.erase(conn);
        }

        Connection::ptr getConnection(const muduo::net::TcpConnectionPtr &conn)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _conns.find(conn);
            if (it == _conns.end())
            {
                return Connection::ptr();
            }
            return it->second;
        }

    private:
        std::mutex _mutex;
        std::unordered_map<muduo::net::TcpConnectionPtr, Connection::ptr> _conns;
    };
    
}
#endif